import _ from 'lodash';
import moment from 'moment';

/**
 * 表示用户提交了输入组件的值。
 * @typeparam V 组件的值的类型。
 */
export interface ISubmitEvent<V = void> {
    value?: V,
};

export const formatNumber = (d?: number | string, fractionDigits: number = 0): string => {
    if (_.isNil(d)) {
        return '';
    } else if (_.isString(d)) {
        return d;
    }

    return d.toFixed(fractionDigits);
};

export const parseNumber = (s: string, fractionDigits: number = 0): number | null => {
    s = _.trim(s);
    if (s === '') {
        return null;
    }

    try {
        return fractionDigits === 0 ? parseInt(s, 10) : parseFloat(s);
    } catch (ignored) {
        return null;
    }
};

export type DateType = 'date' | 'datetime-local' | 'time' | 'week' | 'month' | 'year';

export const formatDate = (d?: Date, type: DateType = 'date'): string => {
    if (_.isNil(d)) {
        return '';
    }

    const m = moment(d);
    switch (type) {
        case 'date':
            return m.format('YYYY-MM-DD');
        case 'datetime-local':
            return m.format('YYYY-MM-DD[T]hh:mm');
        case 'week':
            return m.format('YYYY-[W]ww')
        case 'month':
            return m.format('YYYY-MM');
        case 'year':
            return m.format('YYYY');
        default:
            throw new Error('Unknown date type: ' + type);
    }
};

export const parseDate = (s?: string, type: DateType = 'date'): Date | null => {
    s = _.trim(s);
    if (s === '') {
        return null;
    }

    const m = ((): moment.Moment => {
        switch (type) {
            case 'date':
                return moment(s, ['YYYY-MM-DD', 'YYYY-MM', 'YYYY/MM/DD', 'YYYY/MM', 'YYYYMMDD', 'YYYYMM'], true);
            case 'datetime-local':
                return moment(s, ['YYYY-MM-DD[T]hh:mm', 'YYYY/MM/DD[T]hh:mm', 'YYYYMMDD[T]hh:mm', 'YYYY-MM-DD', 'YYYY-MM', 'YYYY/MM/DD', 'YYYY/MM', 'YYYYMMDD', 'YYYYMM'], true);
            case 'week':
                return moment(s, ['YYYY-[W]ww', 'YYYY-ww', 'YYYY/ww', 'YYYYww'], true);
            case 'month':
                return moment(s, ['YYYY-MM', 'YYYY/MM', 'YYYYMM'], true);
            case 'year':
                return moment(s, ['YYYY'], true);
            default:
                throw new Error('Unknown date type: ' + type);
        }
    })();

    return m.isValid() ? m.toDate() : null;
};

export const fixDateToStart = (d?: Date, type: DateType = 'date'): Date => {
    if (!d) {
        return null;
    }

    const m = moment(d);
    switch (type) {
        case 'date':
        case 'datetime-local':
            return m.startOf('day').toDate();
        case 'time':
            return m.startOf('second').toDate();
        case 'week':
            return m.startOf('week').toDate();
        case 'month':
            return m.startOf('month').toDate();
        case 'year':
            return m.startOf('year').toDate();
        default:
            throw new Error('Unknown type: ' + type);
    }
};

export const fixDateToEnd = (d?: Date, type: DateType = 'date'): Date => {
    if (!d) {
        return null;
    }

    const m = moment(d);
    switch (type) {
        case 'date':
        case 'datetime-local':
            return m.endOf('day').toDate();
        case 'time':
            return m.endOf('second').toDate();
        case 'week':
            return m.endOf('week').toDate();
        case 'month':
            return m.endOf('month').toDate();
        case 'year':
            return m.endOf('year').toDate();
        default:
            throw new Error('Unknown type: ' + type);
    }
};